package com.chen.androidstudy.widget

import android.content.Context
import android.media.AudioManager
import android.media.ToneGenerator
import android.provider.Settings
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.util.AttributeSet
import android.view.HapticFeedbackConstants
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import com.chen.androidstudy.R
import com.chen.androidstudy.databinding.WidgetDialpadBinding
import com.chen.androidstudy.utils.PhoneNumberFormatter

/**
 * @author aljiang
 * @date 2021/2/5
 * @desc
 */
class DialpadView : ConstraintLayout, DialpadKeyButton.OnPressedListener {
    private var mToneEnabled = false
    private var mToneGenerator: ToneGenerator? = null
    private val mToneGeneratorLock = Any()
    private var mTextWatcher: TextWatcher? = null
    private var mDialListener: DialListener? = null
    private lateinit var mContext: Context

    constructor(context: Context) : super(context) {
        init(context)
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        init(context)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        init(context)
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        val contentResolver = context.contentResolver
        mToneEnabled = Settings.System.getInt(
            contentResolver,
            Settings.System.DTMF_TONE_WHEN_DIALING, 1
        ) == 1
        synchronized(mToneGeneratorLock) {
            if (mToneGenerator == null) {
                mToneGenerator = try {
                    ToneGenerator(DIAL_TONE_STREAM_TYPE, TONE_RELATIVE_VOLUME)
                } catch (e: RuntimeException) {
                    null
                }
            }
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        stopTone()
        synchronized(mToneGeneratorLock) {
            if (mToneGenerator != null) {
                mToneGenerator!!.release()
                mToneGenerator = null
            }
        }
    }

    override fun onPressed(view: View, pressed: Boolean) {
        if (view is DialpadKeyButton) {
            if (pressed) {
                val button = view
                performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
                val keycode = button.keyCode
                keyPressed(keycode, button.sound)
            } else {
                stopTone()
            }
        }
    }

    fun addTextChangedListener(watcher: TextWatcher?) {
        mTextWatcher = watcher
    }

    fun setDialListener(listener: DialListener?) {
        mDialListener = listener
    }

    private fun playTone(tone: Int, durationMs: Int) {
        if (!mToneEnabled) {
            return
        }
        val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val ringerMode = audioManager.ringerMode
        if (ringerMode == AudioManager.RINGER_MODE_SILENT
            || ringerMode == AudioManager.RINGER_MODE_VIBRATE
        ) {
            return
        }
        synchronized(mToneGeneratorLock) {
            if (mToneGenerator == null) {
                return
            }
            mToneGenerator!!.startTone(tone, durationMs)
        }
    }

    private fun stopTone() {
        if (!mToneEnabled) {
            return
        }
        synchronized(mToneGeneratorLock) {
            if (mToneGenerator == null) {
                return
            }
            mToneGenerator!!.stopTone()
        }
    }
    private var mBinding : WidgetDialpadBinding?=null
    private fun init(context: Context) {
        mContext = context
        mBinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.widget_dialpad, this, true)
        val count = mBinding!!.dialGridlayout.childCount
        var i = 0
        while (i < count && i < KEYCODE.size) {
            val view: View = mBinding!!.dialGridlayout.getChildAt(i)
            if (view is DialpadKeyButton) {
                val button = view
                button.setup(SOUND[i], KEYCODE[i], NUMBER[i], LETTER[i])
                button.setOnPressedListener(this@DialpadView)
            }
            i++
        }
        mBinding!!.deleteButton.setOnClickListener { v -> keyPressed(KeyEvent.KEYCODE_DEL, -1) }
        mBinding!!.deleteButton.setOnLongClickListener(object : OnLongClickListener {
            override fun onLongClick(v: View?): Boolean {
                mBinding!!.inputPhone.setText("")
                return true
            }
        })
        PhoneNumberFormatter.setPhoneNumberFormattingTextWatcher(context, mBinding!!.inputPhone)
        mBinding!!.inputPhone.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
                if (mTextWatcher != null) {
                    mTextWatcher!!.beforeTextChanged(s, start, count, after)
                }
            }

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                mBinding!!.deleteButton.visibility = if (TextUtils.isEmpty(s)) GONE else VISIBLE
                if (mTextWatcher != null) {
                    mTextWatcher!!.onTextChanged(s, start, before, count)
                }
            }

            override fun afterTextChanged(s: Editable) {
                if (mTextWatcher != null) {
                    mTextWatcher!!.afterTextChanged(s)
                }
            }
        })
    }

    private fun keyPressed(keycode: Int, sound: Int) {
        val event = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
        mBinding!!.inputPhone.onKeyDown(keycode, event)
        val length: Int = mBinding!!.inputPhone.length()
        if (length == mBinding!!.inputPhone.getSelectionStart() && length == mBinding!!.inputPhone.getSelectionEnd()) {
            mBinding!!.inputPhone.setCursorVisible(false)
        }
        if (sound < 0) {
            return
        }
        playTone(sound, TONE_LENGTH_INFINITE)
    }

    fun setPhone(phone: String) {
        mBinding!!.inputPhone.setText("")
        mBinding!!.inputPhone.setText(phone)
        //有2个空格
        var length =  mBinding!!.inputPhone.text!!.length
        mBinding!!.inputPhone.setSelection(length)
    }

    interface DialListener {
        /**
         * 拨号
         *
         * @param type  拨号类型
         * @param phone 号码
         */
        fun dial(type: Int, phone: String?)
    }

    companion object {
        private const val TONE_LENGTH_INFINITE = -1
        private val SOUND = intArrayOf(
            ToneGenerator.TONE_DTMF_1, ToneGenerator.TONE_DTMF_2, ToneGenerator.TONE_DTMF_3,
            ToneGenerator.TONE_DTMF_4, ToneGenerator.TONE_DTMF_5, ToneGenerator.TONE_DTMF_6,
            ToneGenerator.TONE_DTMF_7, ToneGenerator.TONE_DTMF_8, ToneGenerator.TONE_DTMF_9,
            ToneGenerator.TONE_DTMF_S, ToneGenerator.TONE_DTMF_0, ToneGenerator.TONE_DTMF_P
        )
        private val KEYCODE = intArrayOf(
            KeyEvent.KEYCODE_1, KeyEvent.KEYCODE_2, KeyEvent.KEYCODE_3,
            KeyEvent.KEYCODE_4, KeyEvent.KEYCODE_5, KeyEvent.KEYCODE_6,
            KeyEvent.KEYCODE_7, KeyEvent.KEYCODE_8, KeyEvent.KEYCODE_9,
            KeyEvent.KEYCODE_STAR, KeyEvent.KEYCODE_0, KeyEvent.KEYCODE_POUND
        )
        private val NUMBER = arrayOf(
            "1", "2", "3",
            "4", "5", "6",
            "7", "8", "9",
            "*", "0", "#"
        )
        private val LETTER = arrayOf(
            " ", "ABC", "DEF",
            "GHI", "JKL", "MNO",
            "PQRS", "TUV", "WXYZ",
            " ", "+", " "
        )
        private const val DIAL_TONE_STREAM_TYPE = AudioManager.STREAM_DTMF
        private const val TONE_RELATIVE_VOLUME = 80
        const val CALL_AUDIO = 1
        const val CALL_SIM = 2
    }
}